package com.ssy.lingxi.member.merchant.serviceimpl.web;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.basic.UserLoginSourceEnum;
import com.ssy.lingxi.common.constant.member.MemberTypeEnum;
import com.ssy.lingxi.common.constant.member.RoleTypeEnum;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.entity.MenuButtonDO;
import com.ssy.lingxi.member.merchant.entity.MenuDO;
import com.ssy.lingxi.member.merchant.entity.RoleAuthDO;
import com.ssy.lingxi.member.merchant.entity.RoleDO;
import com.ssy.lingxi.member.merchant.model.bo.AuthBO;
import com.ssy.lingxi.member.merchant.model.bo.ButtonBO;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.PageRoleByNameVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.RoleIdVO;
import com.ssy.lingxi.member.merchant.model.vo.platform.request.PlatformRoleAuthMenuVO;
import com.ssy.lingxi.member.merchant.model.vo.platform.request.PlatformRoleAuthStatusVO;
import com.ssy.lingxi.member.merchant.model.vo.platform.request.PlatformRoleAuthVO;
import com.ssy.lingxi.member.merchant.model.vo.platform.response.PlatformButtonQueryVO;
import com.ssy.lingxi.member.merchant.model.vo.platform.response.PlatformRoleAuthButtonVO;
import com.ssy.lingxi.member.merchant.model.vo.platform.response.PlatformRoleAuthQueryVO;
import com.ssy.lingxi.member.merchant.model.vo.platform.response.PlatformRoleAuthTreeVO;
import com.ssy.lingxi.member.merchant.repository.MemberRelationRepository;
import com.ssy.lingxi.member.merchant.repository.MenuRepository;
import com.ssy.lingxi.member.merchant.repository.RoleAuthRepository;
import com.ssy.lingxi.member.merchant.repository.RoleRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseAuthService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCacheService;
import com.ssy.lingxi.member.merchant.service.feign.IPlatformTemplateFeignService;
import com.ssy.lingxi.member.merchant.service.web.IPlatformMenuService;
import com.ssy.lingxi.member.merchant.service.web.IPlatformRoleAuthService;
import com.ssy.lingxi.member.merchant.utils.AuthBOUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 平台后台 - 会员角色权限相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2022-04-14
 */
@Service
public class PlatformRoleAuthServiceImpl implements IPlatformRoleAuthService {
    @Resource
    private IBaseMemberCacheService memberCacheService;

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private RoleAuthRepository roleAuthRepository;

    @Resource
    private MenuRepository menuRepository;

    @Resource
    private MemberRelationRepository relationRepository;

    @Resource
    private IPlatformMenuService platformMenuService;

    @Resource
    private IBaseAuthService baseAuthService;

    @Resource
    private IPlatformTemplateFeignService platformTemplateFeignService;


    /**
     * 根据名称，模糊、分页查询角色列表
     *
     * @param headers Http头部信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<PlatformRoleAuthQueryVO>> pageRoles(HttpHeaders headers, PageRoleByNameVO pageVO) {
        memberCacheService.needLoginFromManagePlatform(headers);
        Specification<RoleDO> specification = (Specification<RoleDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            //去掉平台角色
            list.add(criteriaBuilder.notEqual(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
            if(StringUtils.hasLength(pageVO.getRoleName())) {
                list.add(criteriaBuilder.like(root.get("roleName").as(String.class), "%" + pageVO.getRoleName().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").descending());
        Page<RoleDO> pageList = roleRepository.findAll(specification, page);

        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(roleDO -> {
            PlatformRoleAuthQueryVO queryVO = new PlatformRoleAuthQueryVO();
            queryVO.setRoleId(roleDO.getId());
            queryVO.setRoleName(roleDO.getRoleName());
            queryVO.setBusinessTypeName(roleDO.getBusinessType().getBusinessTypeName());
            queryVO.setMemberTypeName(MemberTypeEnum.getCodeMessage(roleDO.getMemberType().getTypeEnum()));
            queryVO.setRoleTypeName(RoleTypeEnum.getName(roleDO.getRoleType().getTypeEnum()));
            queryVO.setStatus(roleDO.getStatus());
            queryVO.setStatusName(EnableDisableStatus.getNameByCode(roleDO.getStatus()));
            return queryVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 查询角色权限，以树形菜单形式返回
     *
     * @param headers Http头部信息
     * @param idVO    接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<PlatformRoleAuthTreeVO> treeRoleAuth(HttpHeaders headers, RoleIdVO idVO) {
        memberCacheService.needLoginFromManagePlatform(headers);
        RoleDO roleDO = roleRepository.findById(idVO.getRoleId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        List<MenuDO> menus = menuRepository.findBySource(UserLoginSourceEnum.BUSINESS_WEB.getCode());

        PlatformRoleAuthTreeVO authVO = new PlatformRoleAuthTreeVO();
        authVO.setRoleId(roleDO.getId());
        authVO.setRoleName(roleDO.getRoleName());
        authVO.setBusinessTypeName(roleDO.getBusinessType().getBusinessTypeName());
        authVO.setMemberTypeName(MemberTypeEnum.getCodeMessage(roleDO.getMemberType().getTypeEnum()));
        authVO.setRoleTypeName(RoleTypeEnum.getName(roleDO.getRoleType().getTypeEnum()));
        authVO.setStatus(roleDO.getStatus());
        authVO.setStatusName(EnableDisableStatus.getNameByCode(roleDO.getStatus()));
        authVO.setMenus(platformMenuService.transferToTree(menus));
        authVO.setCheckIds(roleDO.getRoleAuth().getAuth().stream().map(AuthBO::getId).collect(Collectors.toList()));
        return Wrapper.success(authVO);
    }

    /**
     * 根据左侧菜单Id，查询右侧按钮列表
     *
     * @param headers  Http头部信息
     * @param menuVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<PlatformRoleAuthButtonVO> getRoleAuthButtons(HttpHeaders headers, PlatformRoleAuthMenuVO menuVO) {
        memberCacheService.needLoginFromManagePlatform(headers);
        RoleDO roleDO = roleRepository.findById(menuVO.getRoleId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        MenuDO menu = menuRepository.findFirstByIdAndSource(menuVO.getMenuId(), UserLoginSourceEnum.BUSINESS_WEB.getCode());
        if(menu == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_DOES_NOT_EXIST);
        }

        PlatformRoleAuthButtonVO buttonVO = new PlatformRoleAuthButtonVO();
        buttonVO.setButtons(menu.getButtons().stream().map(button -> new PlatformButtonQueryVO(button.getId(), button.getName())).collect(Collectors.toList()));

        AuthBO authBO = roleDO.getRoleAuth().getAuth().stream().filter(auth -> auth.getId().equals(menuVO.getMenuId())).findFirst().orElse(null);
        buttonVO.setCheckIds(authBO == null ? new ArrayList<>() : authBO.getButtons().stream().map(ButtonBO::getButtonId).collect(Collectors.toList()));

        return Wrapper.success(buttonVO);
    }

    /**
     * 修改角色权限
     *
     * @param headers    Http头部信息
     * @param roleAuthVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> updateRoleMenus(HttpHeaders headers, PlatformRoleAuthVO roleAuthVO) {
        memberCacheService.needLoginFromManagePlatform(headers);
        RoleDO roleDO = roleRepository.findById(roleAuthVO.getRoleId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        RoleAuthDO roleAuthDO = roleDO.getRoleAuth();
        if(roleAuthDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_AUTH_DOES_NOT_EXIST);
        }

        //无修改则返回
        if(CollectionUtils.isEmpty(roleAuthVO.getMenus())) {
            return Wrapper.success();
        }

        //初始化按钮列表，防止后面代码null值
        roleAuthVO.getMenus().forEach(m -> {
            if(CollectionUtils.isEmpty(m.getButtonIds())) {
                m.setButtonIds(new ArrayList<>());
            }
        });

        //菜单列表
        List<MenuDO> menus = menuRepository.findBySource(UserLoginSourceEnum.BUSINESS_WEB.getCode());

        //校验菜单Id是否正确
        if(roleAuthVO.getMenus().stream().anyMatch(m -> menus.stream().noneMatch(menu -> menu.getId().equals(m.getMenuId())))) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_DOES_NOT_EXIST);
        }

        List<AuthBO> roleAuths = roleAuthDO.getAuth();
        List<AuthBO> copyAuths = AuthBOUtils.copyList(roleAuths);

        //删除的菜单
        roleAuths.removeIf(auth -> roleAuthVO.getMenus().stream().filter(m -> !m.getChecked()).anyMatch(m -> m.getMenuId().equals(auth.getId())));

        //删除的、新增的按钮（重新设置按钮）
        //roleAuths.forEach(auth -> roleAuthVO.getMenus().stream().filter(m -> m.getMenuId().equals(auth.getId()) && m.getChecked()).findFirst().ifPresent(m -> auth.getButtons().removeIf(button -> !m.getButtonIds().contains(button.getButtonId()))));
        roleAuths.forEach(auth ->
                roleAuthVO.getMenus().stream().filter(m -> m.getMenuId().equals(auth.getId()) && m.getChecked()).findFirst().ifPresent(m ->
                        menus.stream().filter(menu -> menu.getId().equals(m.getMenuId())).findFirst().ifPresent(menu ->
                                auth.setButtons(menu.getButtons().stream().filter(button -> m.getButtonIds().contains(button.getId())).map(button -> new ButtonBO(button.getId(), button.getName(), button.getUrl(), button.getCode(), button.getAttrs())).collect(Collectors.toList())))));

        //新增的菜单
        List<AuthBO> newAuthList = roleAuthVO.getMenus().stream().filter(m -> m.getChecked() && roleAuths.stream().noneMatch(auth -> auth.getId().equals(m.getMenuId()))).map(m -> {
            MenuDO menuDO = menus.stream().filter(menu -> menu.getId().equals(m.getMenuId())).findFirst().orElse(null);
            if(menuDO == null) {
                return null;
            }

            List<MenuButtonDO> buttonList = menuDO.getButtons().stream().filter(button -> m.getButtonIds().contains(button.getId())).collect(Collectors.toList());
            return new AuthBO(menuDO.getId(), menuDO.getParentId(), menuDO.getCode(), menuDO.getUrl(), menuDO.getTitle(), menuDO.getOrder(), menuDO.getSource(), menuDO.getAttrs(), buttonList.stream().map(b -> new ButtonBO(b.getId(), b.getName(), b.getUrl(), b.getCode(), b.getAttrs())).collect(Collectors.toList()), menuDO.getDisabled() ? EnableDisableStatus.DISABLE.getCode() : EnableDisableStatus.ENABLE.getCode());
        }).filter(Objects::nonNull).collect(Collectors.toList());

        roleAuths.addAll(newAuthList);


        //如果权限有改变，保存
        if(AuthBOUtils.listNotEqual(roleAuths, copyAuths)) {
            roleAuthDO.setAuth(roleAuths);
            roleAuthRepository.saveAndFlush(roleAuthDO);
        }

        return Wrapper.success();
    }

    /**
     * 修改角色状态
     *
     * @param headers  Http头部信息
     * @param statusVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> updateRoleStatus(HttpHeaders headers, PlatformRoleAuthStatusVO statusVO) {
        memberCacheService.needLoginFromManagePlatform(headers);
        RoleDO roleDO = roleRepository.findById(statusVO.getRoleId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        //如果角色已经有注册会员，不能停用
        if(statusVO.getStatus().equals(EnableDisableStatus.DISABLE.getCode()) && relationRepository.existsBySubRoleIdAndRelType(statusVO.getRoleId(), MemberRelationTypeEnum.PLATFORM.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_CAN_NOT_DISABLE);
        }

        roleDO.setStatus(statusVO.getStatus());
        roleRepository.saveAndFlush(roleDO);

        //异步通知店铺模板服务
        platformTemplateFeignService.notifyRoleStatusChangedAsync(roleDO.getId(), roleDO.getStatus());

        return Wrapper.success();
    }

    /**
     * 更新平台会员权限
     *
     * @param headers Http头部信息
     * @param idVO    接口参数
     * @return 操作结果
     */
    @Override
    public synchronized Wrapper<Void> syncRoleAuth(HttpHeaders headers, RoleIdVO idVO) {
        memberCacheService.needLoginFromManagePlatform(headers);
        RoleDO roleDO = roleRepository.findById(idVO.getRoleId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        //更新平台会员关系、会员、会员角色、用户的权限
        return baseAuthService.rebuildMemberAuthByUpdateRoleAuth(roleDO);
    }
}
